/**
 * Zadanie 3 - klasyfikator DTC z C++ w Pythonie
 * Biblioteka boost::python pozwala używać funkcji i klas zdefiniowanych w C++ w Pythonie.
 * Dostarczyć zbioru szablonów, które będą umożliwiały wykorzystanie drzewa decyzyjnego z biblioteki faif w Pythonie.
 * \author Michał Stankiewicz
 * \author Tomasz Nowak
 */

#include <boost/python.hpp>
#include <faif/learning/DecisionTree.hpp>
#include "zprDecisionTree.hpp"
#include "typedefs.hpp"
#include "zprAttrDomain.hpp"
#include "domainenumeratewrapper.hpp"
#include "zprDecisionTreeTemplate.hpp"

using namespace faif;
using namespace faif::ml;
using namespace boost::python;

typedef ZPRDecisionTreeTemplate< ValueNominalString > stringDTC;
typedef ZPRDecisionTreeTemplate<int> intDTC;
typedef ZPRDecisionTreeTemplate<double> doubleDTC;

BOOST_PYTHON_MODULE(ZPRfaif) {

/**
 * Imports to Python module with methods operating on DTC with template parameter <std::string>
 * Simple way to transform from Python
 */

    class_<DecisionTreeTrainParam>("DecisionTreeTrainParam")
        .def_readwrite("allowedNbrMiscEx", &DecisionTreeTrainParam::allowedNbrMiscEx);
    class_<ZPRDecisionTree>("ZPRDecisionTree")
        .def("zprPassDomain", &ZPRDecisionTree::zprPassDomain)
        .def("zprPassAttributeDomain", &ZPRDecisionTree::zprPassAttributeDomain)
        .def("zprPassAttributeDomainWithName", &ZPRDecisionTree::zprPassAttributeDomainWithName)
        .def("zprPassTrainExamples", &ZPRDecisionTree::zprPassTrainExamples)
        .def("zprPassTestExamples", &ZPRDecisionTree::zprPassTestExample)
		.def("applyTree", &ZPRDecisionTree::applyTree)
		.def("Train", &ZPRDecisionTree::zprTrain)
		.def("Reset", &ZPRDecisionTree::zprReset)
		.def("zprGetCategoryFromDTC", &ZPRDecisionTree::zprGetCategoryFromDTC)
		.def("zprGetAttrDomainsFromDTC", &ZPRDecisionTree::zprGetAttrDomainsFromDTC)
		.def("zprGetCategoryDomainFromDTC", &ZPRDecisionTree::zprGetCategoryDomainFromDTC)
		.def("zprGetCategoryIddFromDTC", &ZPRDecisionTree::zprGetCategoryIddFromDTC)
		.def("zprGetCategoriesFromDTC", &ZPRDecisionTree::zprGetCategoryIddFromDTC)
		;

        to_python_converter<ZPRAttrDomain<ValueNominal<std::string> >,ZPRAttrDomainWrapper<std::string> >();
        to_python_converter<ValueNominal<std::string>, ValueNominalWrapper<std::string> >();
        to_python_converter<DomainEnumerate<ValueNominal<std::string> >, DomainEnumerateWrapper<ValueNominal<std::string> > >();

/**
 * Imports to Python module with methods operating on DTC with template parameter <std::string>
 * Advanced way to transform from Python using Wrapper
 */


    class_<stringDTC>("StringDTC")
        .def("zprPassDomain", &ZPRDecisionTreeTemplate<string>::zprPassDomain)
        .def("zprPassAttributeDomain", &ZPRDecisionTreeTemplate<string>::zprPassAttributeDomain)
        .def("zprPassAttributeDomainWithName", &ZPRDecisionTreeTemplate<string>::zprPassAttributeDomainWithName)
        .def("zprPassTrainExamples", &ZPRDecisionTreeTemplate< ValueNominalString >::zprPassTrainExamples)
        .def("zprPassTestExamples", &ZPRDecisionTreeTemplate< ValueNominal<string> >::zprPassTrainExamples)
		.def("zprApplyTree", &ZPRDecisionTreeTemplate< ValueNominal<string> >::applyTree)
		.def("zprTrainDTC", &ZPRDecisionTreeTemplate< ValueNominal<string> >::zprTrain)
		.def("zprResetDTC", &ZPRDecisionTreeTemplate< ValueNominal<string> >::zprReset)
		.def("zprGetCategoryFromDTC", &ZPRDecisionTreeTemplate< ValueNominal<string> >::zprGetCategoryFromDTC)
		.def("zprGetAttrDomainsFromDTC", &ZPRDecisionTreeTemplate< ValueNominal<string> >::zprGetAttrDomainsFromDTC)
		.def("zprGetCategoryDomainFromDTC", &ZPRDecisionTreeTemplate< ValueNominal<string> >::zprGetCategoryDomainFromDTC)
		.def("zprGetCategoryIddFromDTC", &ZPRDecisionTreeTemplate< ValueNominal<string> >::zprGetCategoryIddFromDTC)
		;

/**
 * Imports to Python module with methods operating on DTC with template parameter int
 * Advanced way to transform from Python using Wrapper
 */

		class_<intDTC>("IntDTC")
        // Methods That take always typename T = string
        .def("PassDomain", &ZPRDecisionTreeTemplate<string>::zprPassDomain)
        .def("PassAttributeDomain", &ZPRDecisionTreeTemplate<string>::zprPassAttributeDomain)
        .def("PassAttributeDomainWithName", &ZPRDecisionTreeTemplate<string>::zprPassAttributeDomainWithName)
        .def("GetAttrDomainsFromDTC", &ZPRDecisionTreeTemplate< ValueNominal<string> >::zprGetAttrDomainsFromDTC)
        // Methods That take other typename T
        .def("PassTrainExamples", &ZPRDecisionTreeTemplate< ValueNominalInt >::zprPassTrainExamples)
        .def("PassTestExamples", &ZPRDecisionTreeTemplate< ValueNominal<int> >::zprPassTrainExamples)
		.def("ApplyTree", &ZPRDecisionTreeTemplate< ValueNominal<int> >::applyTree)
		.def("TrainDTC", &ZPRDecisionTreeTemplate< ValueNominal<int> >::zprTrain)
		.def("ResetDTC", &ZPRDecisionTreeTemplate< ValueNominal<int> >::zprReset)
		.def("GetCategoryFromDTC", &ZPRDecisionTreeTemplate< ValueNominal<int> >::zprGetCategoryFromDTC)
		.def("GetCategoryDomainFromDTC", &ZPRDecisionTreeTemplate< ValueNominal<int> >::zprGetCategoryDomainFromDTC)
		.def("GetCategoryIddFromDTC", &ZPRDecisionTreeTemplate< ValueNominal<int> >::zprGetCategoryIddFromDTC)
		;

/**
 * Imports to Python module with methods operating on DTC with template parameter double
 * Advanced way to transform from Python using Wrapper
 */

		class_<doubleDTC>("DoubleDTC")
        // Methods That take always typename T = string
        .def("PassDomain", &ZPRDecisionTreeTemplate<string>::zprPassDomain)
        .def("PassAttributeDomain", &ZPRDecisionTreeTemplate<string>::zprPassAttributeDomain)
        .def("PassAttributeDomainWithName", &ZPRDecisionTreeTemplate<string>::zprPassAttributeDomainWithName)
        .def("GetAttrDomainsFromDTC", &ZPRDecisionTreeTemplate< ValueNominal<string> >::zprGetAttrDomainsFromDTC)
        // Methods That take other typename T
        .def("PassTrainExamples", &ZPRDecisionTreeTemplate< ValueNominal<double> >::zprPassTrainExamples)
        .def("PassTestExamples", &ZPRDecisionTreeTemplate< ValueNominal<double> >::zprPassTrainExamples)
		.def("ApplyTree", &ZPRDecisionTreeTemplate< ValueNominal<double> >::applyTree)
		.def("TrainDTC", &ZPRDecisionTreeTemplate< ValueNominal<double> >::zprTrain)
		.def("ResetDTC", &ZPRDecisionTreeTemplate< ValueNominal<double> >::zprReset)
		.def("GetCategoryFromDTC", &ZPRDecisionTreeTemplate< ValueNominal<double> >::zprGetCategoryFromDTC)
		.def("GetCategoryDomainFromDTC", &ZPRDecisionTreeTemplate< ValueNominal<double> >::zprGetCategoryDomainFromDTC)
		.def("GetCategoryIddFromDTC", &ZPRDecisionTreeTemplate< ValueNominal<double> >::zprGetCategoryIddFromDTC)
		;

/**
 * Imports to Python module with methods operating on DTC with template parameter given in Wrap
 * Very Advance way to use DTC, but can't be done without overloading operators (especially operator=),
 * and advance operations using methods exactly from faif::ml::DecisionTree
 */

        //ZPRDecisionTreeTemplate< ValueNominalString >::wrap("PythonStringDTC");
        //ZPRDecisionTreeTemplate< ValueNominalString >::wrap("PythonStringDTC");
        //ZPRDecisionTreeTemplate< ValueNominalString >::wrap("PythonStringDTC");

}

